﻿//================================================
//
//                       _oo0oo_
//                      o8888888o
//                      88" . "88
//                      (| -_- |)
//                      0\  =  /0
//                    ___/`---'\___
//                  .' \\|     |// '.
//                 / \\|||  :  |||// \
//                / _||||| -:- |||||- \
//               |   | \\\  -  /// |   |
//               | \_|  ''\---/''  |_/ |
//               \  .-\__  '-'  ___/-. /
//             ___'. .'  /--.--\  `. .'___
//          ."" '<  `.___\_<|>_/___.' >' "".
//         | | :  `- \`.;`\ _ /`;.`/ - ` : | |
//         \  \ `_.   \_ __\ /__ _/   .-` /  /
//     =====`-.____`.___ \_____/___.-`___.-'=====
//                       `=---='
//
//
//     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//               佛祖保佑         永无BUG
//
//
//
//================================================
//
// Created by Huiyi on 2022/11/17
//
//@模块名称 易炫彩WO套件Redis扩展
//@版本   1.1
//@日期   2023-02-11
//@作者   Huiyi
//@模块备注 WO服务器套件
// WEBOAT网络套件的Redis扩展支持库
// 相关问题可进群,易炫彩研究室Q:594165459
// 文档:http://dwiki.hyiy.top/@weboat

#pragma once
#ifndef XL_XEXPAND_DWEBX_MODULE_REDIS_H
//@隐藏{
#define XL_XEXPAND_DWEBX_MODULE_REDIS_H

#ifdef XC_MODUL
#include "module_base.h"
#else 
#endif //  XC_MODUL

#pragma comment(lib,"ws2_32.lib")
#include "redisconnect/RedisConnect.h"

//@隐藏}

//@src "WebOatRedis.cpp"

//@分组{ Redis分组

//@别名 WoRedis指针
typedef std::shared_ptr<RedisConnect> WoRedisConnectPtr;

//@参数 地址 redis服务地址
//@参数 端口 redis服务端口
//@参数 密码	redis服务密码
//@参数 超时 超时时间,ms
//@参数 缓冲区尺寸 单位:字节
//@别名 Wo数据库_Redis初始化(地址,端口,密码,超时,缓冲区尺寸)
inline int WoRedisInit(const char* host, int port, const char* passwd = "", int timeout = 3000, int memsz = 2097152) {
	RedisConnect::Setup(host, port, passwd, timeout, memsz);
	std::shared_ptr<RedisConnect> redis = RedisConnect::Instance();
	redis->POOL_MAXLEN = 8;
	redis->SOCKET_TIMEOUT = 10;
	return redis->getStatus();
};



//@备注 封装的Redis类,自动处理关闭事件
//@别名 WoRedis类
class WoRedisClass
{
public:
	WoRedisClass() { m_ptr = RedisConnect::Instance(); };
	~WoRedisClass() { m_ptr->close(); };


	/*@声明
	//@备注 设置一个键值
	//@参数 键名 存入redis的键
	//@参数 值 存入redis的值
	//@参数 过期时间 多少秒后键过期,0为不过期
	//@别名 置值(键名,值,过期时间)
	int Set(const char* key, 通用型 v, int timeout = 0);
	*/
	//@隐藏{
	template<typename VALUE>
	int Set(const char* key, VALUE val, int outTime = 0) {
		return outTime > 0 ? m_ptr->execute("setex", key, outTime, val) : m_ptr->execute("set", key, val);
	};
	/*@声明
	//@备注 key不存在时设置key的value
	//@参数 键名 存入redis的键
	//@参数 值 存入redis的值
	//@别名 置值_严格(键名,值)
	int Setnx(const char* key, 通用型 v);
	*/
	//@隐藏{
	template<typename VALUE>
	int Setnx(const char* key, VALUE val) {
		return m_ptr->execute("setnx", key, val);
	};
	//@隐藏}
	
	//@备注 返回key所存储的字符串的长度
	//@参数 键名 存入redis的键
	//@别名 取文本值长度(键名)
	int Strlen(const char* key) {
		m_ptr->execute("strlen", key);
		if (m_ptr->m_code>0) {
			return m_ptr->getStatus();
		}
		return 0;
	};
	
	//@备注 切换到指定的数据库，数据库索引号 index 用数字值指定，以 0 作为起始索引值,Redis默认拥有0~15个对应索引的数据库。
	//@别名 切换数据库(索引)
	int Select(int index) {
		return m_ptr->execute("SELECT", index);
	}
	//@备注 获取键值内容
	//@别名 取值(键名,值)
	CXTextA Get(const char* key) {
		return m_ptr->get(key);
	};
	/*@声明
	//@备注 为key设置新value，并返回key的旧value
	//@别名 置新值(键名,新值)
	CXTextA GetSet(const char* key, 通用型 val);
	*/
	//@隐藏{
	template<typename VALUE>
	CXTextA GetSet(const char* key, VALUE val) {
		std::vector<CXTextA> res;
		m_ptr->execute(res,"getset", key, val);
		if (m_ptr->m_code>0&& res.size()>0) {
			return res[0];
		}
		return "";
	};
	//@隐藏}

	/*@声明
	//@备注 获取一个或多个key的value
	//@参数 键列表 例如:key1,key2,key3
	//@别名 取值_批量()(返回列表,键列表)
	int MGet(CXVector<CXTextA>&ret);
	*/
	//@隐藏{
	template<class ...ARGS>
	int MGet(CXVector<CXTextA>&ret, ARGS ...val) {
		std::vector<CXTextA> res;
		m_ptr->execute(res, "mget", val...);
		if (m_ptr->m_code > 0 && res.size() > 0) {
			ret.clear();
			auto retPtr = ret.getVector();
			retPtr->insert(retPtr->end(), res.begin(), res.end());
			//for (auto&i: res) {
			//	ret.clear();
			//	ret.add(i.c_str());
			//}
		}
		return m_ptr->m_code;
	};
	//@隐藏}

	//@备注 删除键值
	//@别名 删除键(键名)
	int Del(const char* key) {
		return m_ptr->del(key);
	};
	//@备注 检查键是否存在
	//@别名 键是否存在(键名)
	int Exists(const char* key) {
		m_ptr->execute("exists", key);
		return m_ptr->getStatus();
	}
	//@备注 为键设置过期时间，以秒计算
	//@别名 置键过期时间(键名,过期时间)
	int Expire(const char* key, int outTime) {
		return  m_ptr->execute("EXPIRE", key, outTime);
	};
	//@备注 以秒为单位返回 key 的剩余过期时间
	//@别名 取键剩余过期时间(键名)
	int GetTTL(const char* key) {
		m_ptr->execute("ttl", key);
		return m_ptr->getStatus();
	};
	//@备注 以毫秒为单位返回 key 的剩余过期时间
	//@别名 取键剩余过期时间_毫秒(键名)
	int GetPTTL(const char* key) {
		m_ptr->execute("pttl", key);
		return m_ptr->getStatus();
	};
	//@备注 获取分布式锁
	//@别名 取分布式锁(锁名,超时)
	bool Lock(const char* lockName, int timeOut = 30) {
		return m_ptr->lock(lockName, timeOut);
	};
	//@备注 释放分布式锁
	//@别名 释放分布式锁(锁名)
	bool UnLock(const char* lockName) {
		return m_ptr->unlock(lockName);
	};

	/*@声明
	//@备注 第一个参数支持重载数组,例如:动态数组<文本型>,数组能取回执行结果
	// .例如: 执行命令(动态数组<文本型>,A"keys",A"*")
	// .或者: 执行命令(A"set",key,value)
	//@参数 指令 一个指令占据一个参数位,例如: GET key -> 执行命令("GET","key")
	//@别名 执行命令()
	int execute(...);
	*/
	//@隐藏{
	template<class DATA_TYPE, class ...ARGS>
	int execute(CXVector<CXTextA>& vec, DATA_TYPE val, ARGS ...args)
	{
		RedisConnect::Command cmd;
		cmd.add(val, args...);
		cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
		if (m_ptr->m_code > 0) {
			vec.clear();
			auto list = cmd.getDataList();
			auto vecPtr = vec.getVector();
			vecPtr->insert(vecPtr->end(), list.begin(), list.end());
			/*for (auto& i : cmd.getDataList()) {
				vec.add(i);
			}*/
		};
		return m_ptr->m_code;
	}
	template<class DATA_TYPE, class ...ARGS>
	int execute(DATA_TYPE val, ARGS ...args)
	{
		RedisConnect::Command cmd;
		cmd.add(val, args...);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}

	//@备注 移除key的过期时间，key将持久保持
	//@别名 持久化键(键名)
	int Persist(const char*key) {
		return m_ptr->execute("persist", key);
	}
	//@备注 查询所有的键名
	//@参数 条件 *为查询所有,例如k*则查询所有k开头的键
	//@别名 取所有键(返回列表,条件)
	int Keys(CXVector<CXTextA>&ret,const char* key="*") {
		std::vector<CXTextA> res;
		m_ptr->execute(res,"keys", key);
		if (m_ptr->m_code>0 && res.size() > 0) {
			ret.clear();
			ret.getVector()->insert(ret.getVector()->end(), res.begin(), res.end());
			/*for (auto& i : res) {
				ret.add(i);
			}*/
		}
		return m_ptr->m_code;
	}
	//@备注 从当前数据库中随机返回一个key
	//@别名 取随机键()
	CXTextA Randomkey() {
		std::vector<CXTextA> res;
		m_ptr->execute(res,"randomkey");
		if (m_ptr->m_code > 0 && res.size() > 0) {
			return res[0];
		}
		return "";
	}
	//@备注 修改key的名称
	//@别名 重命名键(旧名称,新名称)
	int Rename(const char* key, const char* newKey){
		return m_ptr->execute("rename", key, newKey);
	}
	//@备注 当newkey不存在时，将key改名为newkey
	//@别名 重命名键_严格(旧名称,新名称)
	int Renamenx(const char* key, const char* newKey) {
		return m_ptr->execute("renamenx", key, newKey);
	}
	//@备注 将当前数据库的key移动到给定的数据库db当中
	//@参数 新数据库索引 需要移动到的目标数据库索引，数据库索引号 index 用数字值指定，以 0 作为起始索引值,Redis默认拥有0~15个对应索引的数据库。
	//@别名 移动键(键名,新数据库索引)
	int MoveKEY(const char* key,int newDB) {
		return m_ptr->execute("move", key, newDB);
	}
	
	//@备注 将key中存储的数字值增加1
	//@返回 执行成功返回执行命令成功后的值
	//@别名 键自增(键名,返回结果)
	int Incr(const char* key, int* result = NULL) {
		if (m_ptr->execute("incr", key)>0) {
			if (result != NULL) {
				*result = m_ptr->getStatus();
			}
		}
		return 0;
	}
	//@备注 将key中存储的数字值减1 
	//@返回 执行成功返回执行命令成功后的值
	//@别名 键自减(键名,返回结果)
	int Decr(const char* key, int* result = NULL) {
		if (m_ptr->execute("decr", key)>0) {
			if (result != NULL) {
				*result = m_ptr->getStatus();
			}
		}
		return 0;
	}
	//@备注 将key所存储的值加上给定的增量值increment
	//@参数 增加值 increment
	//@返回 执行成功返回执行命令成功后的值
	//@别名 键增加(键名,增加值,返回结果)
	int Incrby(const char* key,int increment, int* result = NULL) {
		if (m_ptr->execute("incrby", key, increment)>0) {
			if (result!=NULL) {
				*result = m_ptr->getStatus();
			}
		}
		return m_ptr->m_code;
	}
	/*@声明
	//@备注 如果key存储的值是一个字符串，append命令将指定的value追加到key原来bvalue的末尾。
	//@别名 拼接数据(键名,拼接的文本)
	int Append(const char* key, 通用型 value);
	*/
	//@隐藏{
	template<typename VAR>
	int Append(const char* key, VAR value) {
		return m_ptr->execute("append", key, value);
	}
	//@隐藏}
	/*@声明
	//@备注 将字典数据映射到redis内
	//@参数 表名 字典在redis内的键
	//@参数 字典数据 字典键对应的字典数据
	//@别名 哈希表_置值(表名,字典数据)
	int HSet(const char* MapKey, CXMap<通用型, 通用型>& mapdata);
	//@备注 将key与value字典映射到redis对应的键内
	//@参数 表名 哈希表在redis内的名称
	//@参数 字段名 字典内键名
	//@参数 值 字典内键对应的值
	//@别名 哈希表_置值Ex(表名,字段名,值)
	int HSet(const char* MapKey, 通用型 key,通用型 value);
	*/
	//@隐藏{
	template<typename KEY, typename VAL>
	int HSet(const char* MapKey, CXMap<KEY, VAL>& vs) {
		RedisConnect::Command cmd;
		cmd.add("HSet", MapKey);
		for (auto iter : *vs.getMap()) {
			cmd.add(iter.first);
			cmd.add(iter.second);
		}
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	template<typename KEY, typename VAL>
	int HSet(const char* MapKey, KEY k, VAL v) {
		return m_ptr->execute("hset", MapKey, k, v);
	}
	//@隐藏}
	/*@声明
	//@备注 删除一个或多个哈希表字段
	//@参数 键名 字段名,支持多参数
	//@别名 哈希表_删除字段(表名,字段名)
	int HDel(const char* MapKey, 通用型 k);
	*/
	//@隐藏{
	template<typename ...KEY>
	int HDel(const char* MapKey, KEY ...k) {
		RedisConnect::Command cmd;
		cmd.add("hdel", MapKey, k...);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}
	/*@声明
	//@备注 查看哈希表key中，指定的字段是否存在
	//@别名 哈希表_字段是否存在(表名,字段名)
	bool HExists(const char* MapKey, 通用型 k);
	*/
	//@隐藏{
	template<typename KEY>
	bool HExists(const char* MapKey, KEY k) {
		if (m_ptr->execute("hexists", MapKey, k)>0) {
			return m_ptr->getStatus()>0;
		}
		return false;
	}
	//@隐藏}
	/*@声明
	//@备注 获取存储在哈希表中指定字段的值
	//@别名 哈希表_取字段值(表名,字段名)
	bool HGet(const char* MapKey, 通用型 k);
	*/
	//@隐藏{
	template<typename KEY>
	CXTextA HGet(const char* MapKey, KEY k) {
		std::vector<CXTextA> ret;
		if (m_ptr->execute(ret,"hget", MapKey, k) > 0&& ret.size()>0) {
			return ret[0];
		}
		return "";
	};
	//@隐藏}	
	/*@声明
	//@备注 获取所有给定字段的值
	//@参数 字段名 返回数据
	//@别名 哈希表_取字段值批量(表名,字段名,返回数据)
	bool HMGet(const char* MapKey, 通用型 k,CXVector<CXTextA>&retList);
	*/
	//@隐藏{
	template<typename ...KEY>
	int HMGet( CXVector<CXTextA>& retList, const char* MapKey, KEY ...k) {
		RedisConnect::Command cmd;
		cmd.add("hmget", MapKey, k...);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout)>0&& cmd.getDataList().size()) {
			retList.clear();
			auto vec = retList.getVector();
			auto& dvec = cmd.getDataList();
			vec->insert(vec->end(), dvec.begin(), dvec.end());
			//std::swap(*vec, cmd.getDataList());
		}
		return m_ptr->m_code;
	};
	//@隐藏}	
	//@备注 获取在哈希表中指定key的所有字段和值
	//@别名 哈希表_取所有字段()
	int HGetall(const char* MapKey,CXMap<CXTextA, CXTextA>&retList) {
		std::vector<CXTextA> ret;
		if (m_ptr->execute(ret, "hgetall", MapKey) > 0 && ret.size() > 0) {
			retList.clear();
			int i = 0;
			while (i < ret.size()) {
				if ( i+2 <= ret.size()) {
					retList[ret[i]]= ret[i+1];
				}
				i+=2;
			}
		}
		return m_ptr->m_code;
	};
	/*@声明
	//@备注 为哈希表key中指定的字段的整数值加上增量increment
	//@参数 返回结果 返回增加之后的值 
	//@别名 哈希表_值增加(键名,字段名,增加值,返回结果)
	int HIncrby(const char* MapKey, 通用型 field, int increment,int* result=NULL);
	*/
	//@隐藏{
	template<typename KEY>
	int HIncrby(const char* MapKey, KEY field, int increment,int* result=NULL) {
		if (m_ptr->execute("hincrby", MapKey, field, increment) > 0) {
			if (result!=NULL) {
				*result = m_ptr->getStatus();
			}
		}
		return m_ptr->m_code;
	}
	//@隐藏}
	
	//@备注 获取所有哈希表中的字段
	//@别名 哈希表_取所有字段名(键名,返回数组)
	int HKeys(const char* MapKey,CXVector<CXTextA>&retList) {
		std::vector<CXTextA> list;
		if (m_ptr->execute(list,"hkeys", MapKey) > 0) {
			retList.clear();
			auto vec = retList.getVector();
			vec->insert(vec->end(), list.begin(), list.end());
		}
		return m_ptr->m_code;
	}
	//@备注 获取哈希表中所有的值
	//@别名 哈希表_取所有字段值(键名,返回数组)
	int HVals(const char* MapKey, CXVector<CXTextA>& retList) {
		std::vector<CXTextA> list;
		if (m_ptr->execute(list, "hvals", MapKey) > 0) {
			retList.clear();
			auto vec = retList.getVector();
			vec->insert(vec->end(), list.begin(), list.end());
		}
		return m_ptr->m_code;
	}
	//@备注 获取哈希表中字段的数量
	//@别名 哈希表_取字段数(键名)
	int HKeys(const char* MapKey) {
		if (m_ptr->execute("hlen", MapKey) > 0) {
			return m_ptr->getStatus();
		}
		return 0;
	}

	//@备注 获取列表长度
	//@别名 列表_取长度(键名)
	int LLen(const char* ListKey) {
		if (m_ptr->execute("llen", ListKey) > 0) {
			return m_ptr->getStatus();
		}
		return 0;
	}
	/*@声明
	//@备注 将一个或多个值插入到列表的头部
	//@参数 数据 欲压入列表的数据,支持无限参数
	//@别名 列表_压入数据(键名,数据)
	int LPush(const char* ListKey, 通用型 v);
	*/
	//@隐藏{
	template<typename ...VAR>
	int LPush(const char* ListKey, VAR...v) {
		RedisConnect::Command cmd;
		cmd.add("lpush", ListKey);
		cmd.add(v...);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}
	
	//@备注 移出并获取列表的第一个元素
	//@别名 列表_弹出数据(键名)
	CXTextA LPop(const char* ListKey) {
		RedisConnect::Command cmd;
		cmd.add("lpop", ListKey);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout)<=0|| cmd.getDataList().size()<1) {
			return "";
		}
		return cmd.getDataList()[0];
	}
	/*@声明
	//@备注 将一个值插入到已存在的列表的头部,列表不存在将失败
	//@别名 列表_压入数据_严格(键名,数据值)
	int LPushx(const char* ListKey, 通用型 v);
	*/
	//@隐藏{
	template<typename VAR>
	int LPushx(const char* ListKey, VAR v) {
		RedisConnect::Command cmd;
		cmd.add("lpushx", ListKey);
		cmd.add(v);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}
	//@备注 获取指定范围内的元素
	//@参数 起始位置 0开始
	//@参数 结束位置 -1为全部数据
	//@别名 列表_取范围数据(返回数据,键名,起始位置,结束位置)
	int LRange(CXVector<CXTextA>&retList,const char* ListKey,int begin=0,int end=-1) {
		retList.clear();
		RedisConnect::Command cmd;
		cmd.add("LRange", ListKey, begin, end);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) <= 0 || cmd.getDataList().size() < 1) {
			return m_ptr->m_code;
		}
		auto vec = retList.getVector();
		auto dvec = cmd.getDataList();
		vec->insert(vec->end(), dvec.begin(), dvec.end());
		return m_ptr->m_code;
	}
	/*@声明
	//@备注 移除列表中所有与值参数相同的元素
	//@返回 返回移除的数量
	//@别名 列表_移除数据(键名,起始位置,值)
	int LRem(const char* ListKey, int count, 通用型 v);
	*/
	//@隐藏{
	template<typename VAR>
	int LRem(const char* ListKey, int count, VAR v) {
		RedisConnect::Command cmd;
		cmd.add("LRem", ListKey,count);
		cmd.add(v);
		cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
		return m_ptr->getStatus();
	}
	//@隐藏}
	/*@声明
	//@备注 通过索引（下标）设置列表元素的值
	//@别名 列表_置数据(键名,下标索引,值)
	int LSet(const char* ListKey,int index, 通用型 v);
	*/
	//@隐藏{
	template<typename VAR>
	int LSet(const char* ListKey,int index, VAR v) {
		RedisConnect::Command cmd;
		cmd.add("LSet", ListKey, index);
		cmd.add(v);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}
	//@备注 对一个列表进行修剪   让列表只保留指定区间内的元素，不在指定区间的元素都将被删除
	//@别名 列表_裁剪(键名)
	int LTrim(const char* ListKey,int begin,int end) {
		RedisConnect::Command cmd;
		cmd.add("LTrim", ListKey, begin, end);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@备注 移除列表的最后一个元素，并将该元素添加到另一个列表并返回
	//@别名 列表_取值合并(旧列表,新列表)
	int RPopLPush(const char* ListKey, const char*outKey,CXVector<CXTextA>*retList=NULL) {
		RedisConnect::Command cmd;
		cmd.add("RPopLPush", ListKey, outKey);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout)>0|| retList!=nullptr) {
			retList->clear();
			auto vec = retList->getVector();
			auto dvec = cmd.getDataList();
			vec->insert(vec->end(), dvec.begin(), dvec.end());
		}
		return m_ptr->m_code;
	}

	//@备注 移出并获取列表的最后一个元素
	//@别名 列表_弹出数据R(键名)
	CXTextA RPop(const char* ListKey) {
		RedisConnect::Command cmd;
		cmd.add("lpop", ListKey);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) <= 0 || cmd.getDataList().size() < 1) {
			return "";
		}
		return cmd.getDataList()[0];
	}
	/*@声明
	//@备注 将一个或多个值插入到列表的尾部
	//@参数 数据 欲压入列表的数据,支持无限参数
	//@别名 列表_压入数据R(键名,数据)
	int RPush(const char* ListKey, 通用型 v);
	*/
	//@隐藏{
	template<typename ...VAR>
	int RPush(const char* ListKey, VAR...v) {
		RedisConnect::Command cmd;
		cmd.add("rpush", ListKey);
		cmd.add(v...);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}
	/*@声明
	//@备注 将一个值插入到已存在的列表的尾部,列表不存在将失败
	//@别名 列表_压入数据r_严格(键名,数据值)
	int RPushx(const char* ListKey, 通用型 v);
	*/
	//@隐藏{
	template<typename VAR>
	int RPushx(const char* ListKey, VAR v) {
		RedisConnect::Command cmd;
		cmd.add("rpushx", ListKey);
		cmd.add(v);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}
	
	/*@声明
	//@备注 向集合添加一个或多个成员
	//@参数 成员 加入集合的成员数据,支持无限参数
	//@别名 集合_加入数据(键名,成员)
	int SAdd(const char* SetKey, 通用型 v);
	*/
	//@隐藏{
	template<typename ...VAR>
	int SAdd(const char* SetKey, VAR...v) {
		RedisConnect::Command cmd;
		cmd.add("SAdd", SetKey);
		cmd.add(v...);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}
	//@备注 获取集合的成员数
	//@别名 集合_取成员数(键名,成员)
	int Scard(const char* SetKey,int* result=NULL) {
		RedisConnect::Command cmd;
		cmd.add("Scard", SetKey);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) && result != nullptr) {
			*result = m_ptr->getStatus();
		}
		return m_ptr->m_code;
	}
	/*@声明
	//@备注 返回一个集合与其他一个或多个集合之间的差异
	//@别名 集合_取差集(返回数据,主集,数据集)
	int Sdiff(CXVector<CXTextA>&retList,const char* SetKey, const char* s);
	*/
	//@隐藏{
	template<typename ...VAR>
	int Sdiff(CXVector<CXTextA>& retList, const char* SetKey, VAR...v) {
		RedisConnect::Command cmd;
		cmd.add("Sdiff", SetKey);
		cmd.add(v...);
		retList.clear();
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) > 0 && cmd.getDataList().size() > 0) {
			auto vec = retList.getVector();
			auto dvec = cmd.getDataList();
			vec->insert(vec->end(), dvec.begin(), dvec.end());
		}
		return m_ptr->m_code;
	};
	//@隐藏}
	/*@声明
	//@备注 返回一个集合与其他一个或多个集合之间的交集
	//@别名 集合_取交集(返回数据,主集,数据集)
	int SInter(CXVector<CXTextA>&retList,const char* SetKey, const char* s);
	*/
	//@隐藏{
	template<typename ...VAR>
	int SInter(CXVector<CXTextA>& retList, const char* SetKey, VAR...v) {
		RedisConnect::Command cmd;
		cmd.add("SInter", SetKey);
		cmd.add(v...);
		retList.clear();
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) > 0 && cmd.getDataList().size() > 0) {
			auto vec = retList.getVector();
			auto dvec = cmd.getDataList();
			vec->insert(vec->end(), dvec.begin(), dvec.end());
		}
		return m_ptr->m_code;
	};
	//@隐藏}

	/*@声明
	//@备注 判断成员元素是否是集合key的成员
	//@别名 集合_成员是否存在(集合键,成员值)
	bool SIsmember(const char* SetKey, 通用型 v);
	*/
	//@隐藏{
	template<typename VAR>
	bool SIsmember(const char* SetKey, VAR v) {
		RedisConnect::Command cmd;
		cmd.add("SIsmember", SetKey);
		cmd.add(v);
		cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
		return m_ptr->getStatus();
	};
	//@隐藏}
	//@备注 返回集合中的所有成员
	//@别名 集合_取所有成员(键名,返回数据)
	int SMembers(const char* SetKey, CXVector<CXTextA>& retList) {
		RedisConnect::Command cmd;
		cmd.add("smembers", SetKey);
		retList.clear();
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) > 0 && cmd.getDataList().size() > 0) {
			auto vec = retList.getVector();
			auto dvec = cmd.getDataList();
			vec->insert(vec->end(), dvec.begin(), dvec.end());
		}
		return m_ptr->m_code;
	};
	/*@声明
	//@备注 将成员元素从源集合移动到目的集合
	//@别名 集合_移动成员(源集合,目的集合,成员值)
	int SMove(const char* source, const char* destination, 通用型 v);
	*/
	//@隐藏{
	template<typename VAR>
	int SMove(const char* source, const char* destination, VAR v) {
		RedisConnect::Command cmd;
		cmd.add("SMove", source, destination);
		cmd.add(v);
		cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
		return m_ptr->getStatus();
	};
	//@隐藏}

	//@备注 返回集合中的一个随机元素,并且将此元素从集合中删除
	//@别名 集合_随机弹出成员(键名)
	CXTextA SPop(const char* SetKey) {
		RedisConnect::Command cmd;
		cmd.add("SPop", SetKey);
		cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) > 0 && cmd.getDataList().size() > 0) {
			return cmd.getDataList()[0];
		}
		return "";
	};
	//@备注 返回集合中一个或多个随机成员
	//@参数 次数 默认1,即取一次随机成员
	//@别名 集合_取随机成员(返回列表,键名,次数)
	int SRandmember(CXVector<CXTextA>& retList,const char* SetKey,int count=1) {
		RedisConnect::Command cmd;
		cmd.add("srandmember", SetKey, count);
		retList.clear();
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) > 0 && cmd.getDataList().size() > 0) {
			auto vec = retList.getVector();
			auto dvec = cmd.getDataList();
			vec->insert(vec->end(), dvec.begin(), dvec.end());
		}
		return m_ptr->m_timeout;
	}
	/*@声明
	//@备注 移除集合中一个或多个成员
	//@参数 成员 要从集合中移出的成员,支持无限参数
	//@别名 集合_移除成员(键名,成员)
	int SRem(const char* SetKey, 通用型 v);
	*/
	//@隐藏{
	template<typename ...VAR>
	int SRem(const char* SetKey, VAR...v) {
		RedisConnect::Command cmd;
		cmd.add("srem", SetKey);
		cmd.add(v...);
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}
	/*@声明
	//@备注 返回一个集合与其他一个或多个集合之间的并集
	//@别名 集合_取并集(返回数据,主集,数据集)
	int SUnion(CXVector<CXTextA>&retList,const char* SetKey, const char* s);
	*/
	//@隐藏{
	template<typename ...VAR>
	int SUnion(CXVector<CXTextA>& retList, const char* SetKey, VAR...v) {
		RedisConnect::Command cmd;
		cmd.add("SUnion", SetKey);
		cmd.add(v...);
		retList.clear();
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) > 0 && cmd.getDataList().size() > 0) {
			auto vec = retList.getVector();
			auto dvec = cmd.getDataList();
			vec->insert(vec->end(), dvec.begin(), dvec.end());
		}
		return m_ptr->m_code;
	};
	//@隐藏}
	
	/*@声明
	//@备注 向有序集合添加一个或多个成员，或者更新已经存在的分数
	//@别名 有序集合_添加成员(键名,列表数据)
	int ZAdd(const char* SetKey, CXMap<通用型, double>& mapList);
	*/
	//@隐藏{
	template<typename VAL>
	int ZAdd(const char* SetKey,CXMap<VAL, double>& mapList) {
		RedisConnect::Command cmd;
		cmd.add("ZAdd", SetKey);
		for (auto iter = mapList.begin(); iter != mapList.end(); iter++) {
			cmd.add(iter->second);
			cmd.add(iter->first);
		};
		return cmd.getResult(m_ptr.get(), m_ptr->m_timeout);
	}
	//@隐藏}
	//@备注 获取有序集合的成员数
	//@别名 有序集合_取成员数(键名,成员)
	int ZCard(const char* SetKey, int* result = NULL) {
		RedisConnect::Command cmd;
		cmd.add("zcard", SetKey);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) && result != nullptr) {
			*result = m_ptr->getStatus();
		}
		return m_ptr->m_code;
	}
	//@备注 计算在有序集合中指定区间分数的成员数
	//@别名 有序集合_取区间分数成员数(键名,最小分数,最大分数,返回值)
	int zcount(const char* SetKey, double min, double max, int* result = NULL) {
		RedisConnect::Command cmd;
		cmd.add("zcount", SetKey, min, max);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) && result != nullptr) {
			*result = m_ptr->getStatus();
		}
		return m_ptr->m_code;
	};

	/*@声明
	//@备注 返回有序集合中，成员的分数值
	//@别名 有序集合_取成员分数(键名,成员,返回值)
	int ZScore(const char* SetKey, 通用型 member,int* result=NULL);
	*/
	//@隐藏{
	template<typename VAL>
	int ZScore(const char* SetKey, VAL v, double* result=NULL) {
		RedisConnect::Command cmd;
		cmd.add("ZScore", SetKey, v);
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout)>0 && result!=nullptr && cmd.getDataList().size()>0) {
			*result = atof(cmd.getDataList()[0]);
		}
		return m_ptr->m_code;
	}
	//@隐藏}

	//@备注 通过索引区间返回有序集合指定区间内的成员
	//@别名 有序集合_取区间成员(键名,起始索引,结束索引,返回数据)
	int ZRange(const char* SetKey, int start, int stop, CXMap<CXTextA, double>& mapList) {
		RedisConnect::Command cmd;
		cmd.add("ZRange", SetKey, start, stop, "withscores");
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) > 0 && cmd.getDataList().size() > 0) {
			mapList.clear();
			auto dvec = cmd.getDataList();
			if (dvec.size()%2!=0) {
				return m_ptr->m_code;
			}
			for (size_t i = 0; i < dvec.size(); i+=2) {
				mapList[dvec[i]] = atof(dvec[i + 1]);
			}
		}
		return m_ptr->m_code;
	};

	//@备注 返回有序集合中指定分数区间内的成员，分数从高到低排序
	//@别名 有序集合_取分数区间成员(键名,起始索引,结束索引,返回数据)
	int ZRevrangebyscore(const char* SetKey, int max, int min, CXMap<CXTextA, double>& mapList) {
		RedisConnect::Command cmd;
		cmd.add("ZRevrangebyscore", SetKey, max, min, "withscores");
		if (cmd.getResult(m_ptr.get(), m_ptr->m_timeout) > 0 && cmd.getDataList().size() > 0) {
			mapList.clear();
			auto dvec = cmd.getDataList();
			if (dvec.size() % 2 != 0) {
				return m_ptr->m_code;
			}
			for (size_t i = 0; i < dvec.size(); i += 2) {
				mapList[dvec[i]] = atof(dvec[i + 1]);
			}
		}
		return m_ptr->m_code;
	}

	//@别名 取最后错误代码()
	int GetErrorCode() {
		return m_ptr->getErrorCode();
	};
	//@别名 取最后错误文本()
	CXTextA GetErrorString() {
		return m_ptr->getErrorString();
	};

protected:

private:
	WoRedisConnectPtr m_ptr;
};


//@分组}


#endif